﻿//------------------------------------------------------------------------------
// <copyright file="KinectDepthViewer.xaml.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
//------------------------------------------------------------------------------

namespace Microsoft.Samples.Kinect.WpfViewers
{
    using System.Windows;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using Microsoft.Kinect;
using System.Windows.Controls;
using KinectApplication;

    /// <summary>
    /// Interaction logic for KinectDepthViewer.xaml
    /// </summary>
    public partial class KinectDepthViewer : ImageViewer
    {
        // color divisors for tinting depth pixels
        private static readonly int[] IntensityShiftByPlayerR = { 1, 2, 0, 2, 0, 0, 2, 0 };
        private static readonly int[] IntensityShiftByPlayerG = { 1, 2, 2, 0, 2, 0, 0, 1 };
        private static readonly int[] IntensityShiftByPlayerB = { 1, 0, 2, 2, 0, 2, 0, 2 };

        private const int AlphaIndex = 3;
        private const int RedIndex = 2;
        private const int GreenIndex = 1;
        private const int BlueIndex = 0;
        private static readonly int Bgr32BytesPerPixel = (PixelFormats.Bgr32.BitsPerPixel + 7) / 8;
        private static readonly int Bgra32BytesPerPixel = (PixelFormats.Bgra32.BitsPerPixel + 7) / 8;

      //  private static DepthImageFormat lastImageFormat;
      //  private static short[] pixelData;

        // We want to control how depth data gets converted into false-color data
        // for more intuitive visualization, so we keep 32-bit color frame buffer versions of
        // these, to be updated whenever we receive and process a 16-bit frame.
        private static byte[] depthFrame32;
        private static WriteableBitmap outputDepthBitmap;
   
        private static Image depthImage;

        public KinectDepthViewer()
        {
            InitializeComponent();

            depthImage = kinectDepthImage;
        }

        //this little show depth takes 70% of the processing powah
        public static void ShowDepth(short[] array, int width, int height, bool onlyPlayer, short MinDepth)
        {
            if (Debugging.TestMode == false)
            {
                depthFrame32 = new byte[width * height * Bgra32BytesPerPixel];

                byte[] convertedDepthBits = onlyPlayer ? ConvertDepthFrameOnlyPlayer(array, MinDepth) : ConvertDepthFrame(array);


                // A WriteableBitmap is a WPF construct that enables resetting the Bits of the image.
                // This is more efficient than creating a new Bitmap every frame.
                if (outputDepthBitmap == null)
                {
                    outputDepthBitmap = new WriteableBitmap(width, height, 96, 96, PixelFormats.Bgra32, null);

                    depthImage.Source = outputDepthBitmap;
                }

                outputDepthBitmap.WritePixels(new Int32Rect(0, 0, width, height), convertedDepthBits, width * Bgra32BytesPerPixel, 0);
            }
        }

        // Converts a 16-bit grayscale depth frame which includes player indexes into a 32-bit frame
        // that displays different players in different colors
        private static byte[] ConvertDepthFrame(short[] depthFrame)
        {
            // int tooNearDepth = depthStream.TooNearDepth;
            // int tooFarDepth = depthStream.TooFarDepth;
            //  int unknownDepth = depthStream.UnknownDepth;

            for (int i16 = 0, i32 = 0; i16 < depthFrame.Length && i32 < depthFrame32.Length; i16++, i32 += 4)
            {
                int player = depthFrame[i16] & DepthImageFrame.PlayerIndexBitmask;
                int realDepth = depthFrame[i16] >> DepthImageFrame.PlayerIndexBitmaskWidth;

                // transform 13-bit depth information into an 8-bit intensity appropriate
                // for display (we disregard information in most significant bit)
                byte intensity = (byte)(~(realDepth >> 4));

                //if (player == 0 && realDepth == 0)
                //{
                //    // white 
                //    depthFrame32[i32 + RedIndex] = 255;
                //    depthFrame32[i32 + GreenIndex] = 255;
                //    depthFrame32[i32 + BlueIndex] = 255;
                //}
                //else if (player == 0 && realDepth == tooFarDepth)
                //{
                //    // dark purple
                //    depthFrame32[i32 + RedIndex] = 66;
                //    depthFrame32[i32 + GreenIndex] = 0;
                //    depthFrame32[i32 + BlueIndex] = 66;
                //}
                //else if (player == 0 && realDepth == unknownDepth)
                //{
                //    // dark brown
                //    depthFrame32[i32 + RedIndex] = 66;
                //    depthFrame32[i32 + GreenIndex] = 66;
                //    depthFrame32[i32 + BlueIndex] = 33;
                //}
                //else
                //{
                // tint the intensity by dividing by per-player values
                depthFrame32[i32 + AlphaIndex] = (byte)(intensity >> IntensityShiftByPlayerR[player]);
                depthFrame32[i32 + RedIndex] = (byte)(intensity >> IntensityShiftByPlayerR[player]);
                depthFrame32[i32 + GreenIndex] = (byte)(intensity >> IntensityShiftByPlayerG[player]);
                depthFrame32[i32 + BlueIndex] = (byte)(intensity >> IntensityShiftByPlayerB[player]);










                // }
            }

            return depthFrame32;
        }

        //show only the player
        private static byte[] ConvertDepthFrameOnlyPlayer(short[] depthFrame, short MinDepth)
        {

            for (int i16 = 0, i32 = 0; i16 < depthFrame.Length && i32 < depthFrame32.Length; i16++, i32 += 4)
            {
                int player = depthFrame[i16] & DepthImageFrame.PlayerIndexBitmask;

                if (depthFrame[i16] < -8)
                {
                    short value = (short)(255 - (MinDepth - depthFrame[i16]));

                    depthFrame32[i32 + AlphaIndex] = (byte)value;
                    depthFrame32[i32 + BlueIndex] = (byte)value;
                    depthFrame32[i32 + GreenIndex] = (byte)value;
                    depthFrame32[i32 + RedIndex] = (byte)value;
                }
                else if (player != 0)
                {

                    int realDepth = depthFrame[i16] >> DepthImageFrame.PlayerIndexBitmaskWidth;

                    if (realDepth > 0)
                    {
                        byte intensity = (byte)(~(realDepth >> 4));

                        depthFrame32[i32 + AlphaIndex] = (byte)255;
                        depthFrame32[i32 + GreenIndex] = (byte)(-realDepth);
                        depthFrame32[i32 + BlueIndex] = (byte)(realDepth >> 2);
                        depthFrame32[i32 + RedIndex] = (byte)(realDepth >> 4);
                    }
                }

            }

            return depthFrame32;
        }


        protected override void OnKinectChanged(KinectSensor oldKinectSensor, KinectSensor newKinectSensor)
        {
            if (oldKinectSensor != null)
            {
                kinectDepthImage.Source = null;
            }


        }

    }
}
